{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 内置回调处理器\n",
    "\n",
    "为了简化开发过程，LangChain提供了一系列内置的回调处理器，比如我们运行一个 Agent ，它的底层都使用到了`StdOutCallbackHandler`。例如我们在下面代码中设置 verbose=True ，在 Agent 运行时，也就是事件发生时将 Agent 的相关信息打印到标准输出（通常是控制台或命令行界面）。\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "os.environ[\"OPENAI_API_KEY\"] = \"填入你的OpenAI密钥\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3m I need to add 9 and 7\n",
      "Action: Calculator\n",
      "Action Input: 9+7\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3mAnswer: 16\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
      "Final Answer: 9+7 = 16\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'9+7 = 16'"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.agents import load_tools\n",
    "from langchain.agents import initialize_agent\n",
    "from langchain.agents import AgentType\n",
    "\n",
    "from langchain.llms import OpenAI\n",
    "llm = OpenAI()\n",
    "\n",
    "tools = load_tools([\"llm-math\"], llm=llm)\n",
    "agent = initialize_agent(\n",
    "    tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,verbose=True\n",
    ")\n",
    "agent.run(\n",
    "    \"9+7\"\n",
    ")\n",
    "\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们在命令行界面就可以看到以 Entering new AgentExecutor chain... 开始，以 Finished chain 结尾的标准输出。"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "但是如果设置为 verbose=False ，我们在命令行界面只会看到大语言模型最终的回答。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Retrying langchain.llms.openai.completion_with_retry.<locals>._completion_with_retry in 4.0 seconds as it raised RateLimitError: Rate limit reached for default-text-davinci-003 in organization org-VEnNKTtyYXEBdaVF7u4kNojB on requests per min. Limit: 3 / min. Please try again in 20s. Contact us through our help center at help.openai.com if you continue to have issues. Please add a payment method to your account to increase your rate limit. Visit https://platform.openai.com/account/billing to add a payment method..\n",
      "Retrying langchain.llms.openai.completion_with_retry.<locals>._completion_with_retry in 4.0 seconds as it raised RateLimitError: Rate limit reached for default-text-davinci-003 in organization org-VEnNKTtyYXEBdaVF7u4kNojB on requests per min. Limit: 3 / min. Please try again in 20s. Contact us through our help center at help.openai.com if you continue to have issues. Please add a payment method to your account to increase your rate limit. Visit https://platform.openai.com/account/billing to add a payment method..\n",
      "Retrying langchain.llms.openai.completion_with_retry.<locals>._completion_with_retry in 4.0 seconds as it raised RateLimitError: Rate limit reached for default-text-davinci-003 in organization org-VEnNKTtyYXEBdaVF7u4kNojB on requests per min. Limit: 3 / min. Please try again in 20s. Contact us through our help center at help.openai.com if you continue to have issues. Please add a payment method to your account to increase your rate limit. Visit https://platform.openai.com/account/billing to add a payment method..\n",
      "Retrying langchain.llms.openai.completion_with_retry.<locals>._completion_with_retry in 8.0 seconds as it raised RateLimitError: Rate limit reached for default-text-davinci-003 in organization org-VEnNKTtyYXEBdaVF7u4kNojB on requests per min. Limit: 3 / min. Please try again in 20s. Contact us through our help center at help.openai.com if you continue to have issues. Please add a payment method to your account to increase your rate limit. Visit https://platform.openai.com/account/billing to add a payment method..\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'9+7 = 16'"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent = initialize_agent(\n",
    "    tools, llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,verbose=False\n",
    ")\n",
    "agent.run(\n",
    "    \"9+7\"\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### LLMChain 添加一个内置回调处理器"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们还可以给链组件和 Agent 添加内置或者自定义的回调处理器。比如我们给一个基础的链组件 LLMChain 添加一个内置回调处理器： StdOutCallbackHandler。我们可以先创建一个链组件。在初始化 LLMChain 的时候，这个链组件没有设置内置回调处理器，也不能设置 verbose=True。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n\\n上海的旅游景点有：\\n1. 东方明珠广播电视塔\\n2. 外滩\\n3. 上海野生动物园\\n4. 上海迪士尼度假区\\n5. 上海科技馆\\n6. 南京路步行街\\n7. 外白渡桥\\n8. 上海浦东新区\\n9. 豫园\\n10. 南京路商业街\\n11. 上海博物馆\\n12. 上海世博园\\n13. 上海环球金融中心\\n14. 上海东方明珠\\n15. 上海市政府大'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "from langchain.chains import LLMChain\n",
    "from langchain.llms import OpenAI\n",
    "\n",
    "llm_chain = LLMChain(llm=OpenAI(),\n",
    "                     prompt=PromptTemplate.from_template(\"{input}\"))\n",
    "llm_chain.run('上海的旅游景点有哪些？')"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行 LLMChain 后，大语言模型回答的是：\n",
    "\n",
    "上海的旅游景点有：\\n\\n1. 上海迪士尼乐园\\n2. 东方明珠塔\\n3. 南京路步行街\\n4. 上海外滩\\n5. 上海野生动物园\\n6. 外白渡桥\\n7. 南京路商业街\\n8. 上海科技馆\\n9. 上海老城隍庙\\n10. 上海博物馆\\n11. 上海浦江夜游\\n12. 上海水上乐园\\n13. 上海徐汇森林公园\\n14. 上海金茂大厦\\n...\n",
    "\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果我们想要监控这个链组件，添加一些回调逻辑，比如我们想要看到命令行界面的运行过程。那么我们可以给这个链组件增加一个回调处理器。这里我们导入内置的 StdOutCallbackHandler，并且创建创建它的实例 handler_1 ，初始化回调处理器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.callbacks import StdOutCallbackHandler\n",
    "handler_1 = StdOutCallbackHandler()"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这样我们就给一个普通的链组件添加了一个回调处理器，内置的 StdOutCallbackHandler 完成的是做标准的输出。当我们继续运行这个链组件之后，我们在命令行界面就可以看到以 Entering new AgentExecutor chain... 开始，以 Finished chain 结尾的标准输出。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new LLMChain chain...\u001b[0m\n",
      "Prompt after formatting:\n",
      "\u001b[32;1m\u001b[1;3m上海的旅游景点有哪些？\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\n\\n上海的旅游景点有：\\n\\n1. 东方明珠广播电视塔；\\n2. 外滩；\\n3. 南京路步行街；\\n4. 上海迪士尼乐园；\\n5. 南京西路步行街；\\n6. 豫园；\\n7. 上海虹桥国际机场；\\n8. 上海野生动物园；\\n9. 上海海洋水族馆；\\n10. 上海科技馆；\\n11. 上海世博园；\\n12. 蓝色港湾；\\n13'"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "llm_chain = LLMChain(llm=OpenAI(),callbacks=[handler_1],verbose=False,\n",
    "                     prompt=PromptTemplate.from_template(\"{input}\"))\n",
    "llm_chain.run('上海的旅游景点有哪些？')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n\\n1. 东方明珠塔\\n2. 上海迪士尼度假区\\n3. 上海科技馆\\n4. 上海野生动物园\\n5. 上海世纪公园\\n6. 上海海洋水族馆\\n7. 上海老街\\n8. 上海外滩\\n9. 上海博物馆\\n10. 上海金茂大厦'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "llm_chain = LLMChain(llm=OpenAI(),callbacks=[],verbose=False,\n",
    "                     prompt=PromptTemplate.from_template(\"{input}\"))\n",
    "llm_chain.run('上海的旅游景点有哪些？')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
